package com.shrcl.engineerprocess.domain.impl;

import com.shrcl.engineerprocess.domain.Engineer;
import com.shrcl.engineerprocess.domain.EngineerProjectAssignment;
import com.shrcl.engineerprocess.domain.EngineerProjectAssignmentDAO;
import com.shrcl.engineerprocess.domain.EngineerProjectAssignmentStatus;
import com.shrcl.engineerprocess.domain.EngineerWorkOrder;
import com.shrcl.engineerprocess.domain.WorkSummary;
import com.shrcl.engineerprocess.domain.impl.EngineerImpl;
import com.shrcl.engineerprocess.domain.impl.EngineerWorkOrderImpl;
import com.shrcl.engineerprocess.domain.impl.WorkSummaryImpl;
import com.shrcl.engineerprocess.domain.proxy.EngineerProjectAssignmentProxy;
import com.uniquesoft.uidl.validation.Validates;
import edu.fudan.langlab.domain.statemachine.ModelObjectLogService;
import edu.fudan.mylang.pf.BaseModelObject;
import edu.fudan.mylang.pf.IObjectFactory;
import edu.fudan.mylang.pf.ISystemDateTimeService;
import edu.fudan.mylang.utils.DateUtil;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.hibernate.annotations.DiscriminatorOptions;
import org.springframework.beans.factory.BeanFactory;

@Entity
@DiscriminatorValue("ENGINEERPROJECTASSIGNMENT_TYPE")
@DiscriminatorOptions(force = true)
@DiscriminatorColumn(length = 64)
@Table(name = "engineerprojectassignment")
public class EngineerProjectAssignmentImpl extends BaseModelObject implements EngineerProjectAssignment {
  public EngineerProjectAssignmentImpl() {
    super();
  }
  
  public EngineerProjectAssignmentImpl(final EngineerWorkOrder workOrder) {
    super();
    this.workOrder = workOrder;
  }
  
  private EngineerProjectAssignmentStatus Status;
  
  public EngineerProjectAssignmentStatus getStatus() {
    return this.Status;
  }
  
  private ModelObjectLogService getModelObjectLogService() {
    return getBeanFactory().getBean(ModelObjectLogService.class);
  }
  
  private void _start() {
    WorkSummary workSummary=WorkSummaryImpl.create(getObjectFactory());
    this.dailySummary = workSummary;
    Status=EngineerProjectAssignmentStatus.executing;
  }
  
  public void start() {
    if(Status==null){
    	_start();
    	getModelObjectLogService().createLog(this,"Status","Start");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectAssignmentEventsManager.class).fireStarted(this);					
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException("allready started");
    }
  }
  
  private void _checkExecutingTimer() {
    
    BeanFactory _beanFactory = this.getBeanFactory();
    final ISystemDateTimeService dateTimeService = _beanFactory.<ISystemDateTimeService>getBean(ISystemDateTimeService.class);
    Date _day = dateTimeService.today();
    boolean _greaterEqualsThan = (this.startDate.compareTo(_day) >= 0);
    if (_greaterEqualsThan) {
      Status=EngineerProjectAssignmentStatus.executing;
      Boolean _isCreated = this.workOrder.isCreated();
      if ((_isCreated).booleanValue()) {
        this.workOrder.$startexecute(this);
      }
    }
  }
  
  public void checkExecutingTimer() {
    if(Status==EngineerProjectAssignmentStatus.created){
    	_checkExecutingTimer();
    	getModelObjectLogService().createLog(this,"Status","checkExecutingTimer");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectAssignmentEventsManager.class).fireCheckExecutingTimer(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _startExecute() {
    
    Status=EngineerProjectAssignmentStatus.executing;
    Boolean _isCreated = this.workOrder.isCreated();
    if ((_isCreated).booleanValue()) {
      this.workOrder.$startexecute(this);
    }
  }
  
  public void startExecute() {
    if(Status==EngineerProjectAssignmentStatus.created){
    	_startExecute();
    	getModelObjectLogService().createLog(this,"Status","startExecute");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectAssignmentEventsManager.class).fireStartExecute(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _finish() {
    
    Status=EngineerProjectAssignmentStatus.finished;
    this.workOrder.$taskFinish(this);
  }
  
  public void finish() {
    if(Status==EngineerProjectAssignmentStatus.executing){
    	_finish();
    	getModelObjectLogService().createLog(this,"Status","finish");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectAssignmentEventsManager.class).fireFinish(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _updateV(final Procedure1<? super EngineerProjectAssignment> updater) {
    
    updater.apply(this);
    this.checkValid();
  }
  
  public void updateV(final Procedure1<? super EngineerProjectAssignment> updater) {
    if(Status==EngineerProjectAssignmentStatus.executing){
    	_updateV(updater);
    	getModelObjectLogService().createLog(this,"Status","updateV");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectAssignmentEventsManager.class).fireUpdateV(this,updater);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _doSummary(final String summary) {
    
    Date _now = DateUtil.now();
    this.dailySummary.setDate(_now);
    this.dailySummary.setSummary(summary);
  }
  
  public void doSummary(final String summary) {
    if(Status==EngineerProjectAssignmentStatus.executing){
    	_doSummary(summary);
    	getModelObjectLogService().createLog(this,"Status","doSummary");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectAssignmentEventsManager.class).fireDoSummary(this,summary);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _cancel() {
    
    Status=EngineerProjectAssignmentStatus.cancelled;
    this.workOrder.$taskCancel(this);
  }
  
  public void cancel() {
    if(Status==EngineerProjectAssignmentStatus.created||Status==EngineerProjectAssignmentStatus.executing){
    	_cancel();
    	getModelObjectLogService().createLog(this,"Status","cancel");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectAssignmentEventsManager.class).fireCancel(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  public Boolean isExecuting() {
    return com.shrcl.engineerprocess.domain.EngineerProjectAssignmentStatus.executing==Status;
  }
  
  public Boolean isFinished() {
    return com.shrcl.engineerprocess.domain.EngineerProjectAssignmentStatus.finished==Status;
  }
  
  public Boolean isCancelled() {
    return com.shrcl.engineerprocess.domain.EngineerProjectAssignmentStatus.cancelled==Status;
  }
  
  public Boolean isCreated() {
    return com.shrcl.engineerprocess.domain.EngineerProjectAssignmentStatus.created==Status;
  }
  
  @JoinColumn(name = "workOrder_id")
  @ManyToOne(targetEntity = EngineerWorkOrderImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private EngineerWorkOrder workOrder;
  
  public EngineerWorkOrder getWorkOrder() {
    return this.workOrder;
  }
  
  public EngineerProjectAssignment setWorkOrder(final EngineerWorkOrder workOrder) {
    this.workOrder = workOrder;
    return this;			
    
  }
  
  private Date startDate;
  
  public Date getStartDate() {
    return this.startDate;
  }
  
  public EngineerProjectAssignment setStartDate(final Date startDate) {
    this.startDate = startDate;
    return this;			
    
  }
  
  private Date endDate;
  
  public Date getEndDate() {
    return this.endDate;
  }
  
  public EngineerProjectAssignment setEndDate(final Date endDate) {
    this.endDate = endDate;
    return this;			
    
  }
  
  @JoinColumn(name = "engineer_id")
  @ManyToOne(targetEntity = EngineerImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private Engineer engineer;
  
  public Engineer getEngineer() {
    return this.engineer;
  }
  
  public EngineerProjectAssignment setEngineer(final Engineer engineer) {
    this.engineer = engineer;
    return this;			
    
  }
  
  @JoinColumn(name = "dailySummary_id")
  @OneToOne(targetEntity = WorkSummaryImpl.class, cascade = CascadeType.ALL)
  private WorkSummary dailySummary;
  
  public WorkSummary getDailySummary() {
    return this.dailySummary;
  }
  
  public EngineerProjectAssignment setDailySummary(final WorkSummary dailySummary) {
    this.dailySummary = dailySummary;
    return this;			
    
  }
  
  public void checkValid() {
    BeanFactory _beanFactory = this.getBeanFactory();
    final EngineerProjectAssignmentDAO dao = _beanFactory.<EngineerProjectAssignmentDAO>getBean(EngineerProjectAssignmentDAO.class);
    Integer _findingCount = dao.findingCount(this.startDate, this.endDate, this.engineer);
    boolean _lessEqualsThan = ((_findingCount).intValue() <= 1);
    Validates.Assert(_lessEqualsThan, "\u51B2\u7A81");
  }
  
  public static EngineerProjectAssignment create(final EngineerWorkOrder workOrder, final IObjectFactory objectFactory) {
    com.shrcl.engineerprocess.domain.EngineerProjectAssignment engineerProjectAssignment = new com.shrcl.engineerprocess.domain.impl.EngineerProjectAssignmentImpl(
    	workOrder
    );
    objectFactory.create(engineerProjectAssignment);
    engineerProjectAssignment.start();
    return engineerProjectAssignment;			
    
  }
  
  public static EngineerProjectAssignment createEngineerProjectAssignmentImpl(final EngineerWorkOrder workOrder, final IObjectFactory objectFactory, final Procedure1<EngineerProjectAssignment> init) {
    com.shrcl.engineerprocess.domain.EngineerProjectAssignment engineerProjectAssignment = new com.shrcl.engineerprocess.domain.impl.EngineerProjectAssignmentImpl(
    	workOrder
    );
    objectFactory.create(engineerProjectAssignment);
    init.apply(engineerProjectAssignment);
    engineerProjectAssignment.start();
    
    return engineerProjectAssignment;			
    
  }
  
  public EngineerProjectAssignmentProxy toProxy() {
    com.shrcl.engineerprocess.domain.proxy.EngineerProjectAssignmentProxy proxy = new com.shrcl.engineerprocess.domain.proxy.EngineerProjectAssignmentProxy();
    proxy.setId(this.getId());
    if(this instanceof edu.fudan.mylang.pf.INamedModelObject){
    	proxy.setName(((edu.fudan.mylang.pf.INamedModelObject)this).getEntityName());
    }
    proxy.setStatus(this.getStatus().name());
    return proxy;
    
  }
}
